import logging

from django.http import JsonResponse
from django.views import View
from django_redis import get_redis_connection

from goods.models import SKU
from meiduo.utils.views import LoginRequiredMixin
from users.models import Address
from .models import OrderGoods, OrderInfo
from django.utils import timezone
from django_redis import get_redis_connection
from decimal import Decimal
from meiduo.apps.carts.utils import *
from django.db import transaction
import json

logger = logging.getLogger("django")


# Create your views here.

class OrderSettlementView(LoginRequiredMixin, View):

    def get(self, request):
        """
        结算订单
        :param request:
        :return:
        """
        user = request.user  # 获取用户对象
        redis_conn = get_redis_connection("carts")  # 获取存储购物车数据的redis连接对象

        '''获取购物车勾选的商品'''
        carts_sku = redis_conn.hgetall(f"carts_{user.id}")  # 从数据库获取购物车的商品信息(ID和数量)
        selected_sku_id = redis_conn.smembers(f"selected_{user.id}")  # 从数据库获取勾选的商品id
        skus = []  # 定义列表存储商品信息
        for sku_id in selected_sku_id:
            count = int(carts_sku[sku_id])
            sku_id = int(sku_id)
            try:
                sku = SKU.objects.get(id=sku_id)  # 获取商品对象
            except Exception as e:
                logger.error(f"获取商品(ID:{sku_id})失败:{e}")
                continue
            skus.append({
                "id": sku.id,
                "name": sku.name,
                "default_image_url": sku.default_image_url,
                "count": count,
                "price": sku.price
            })

        '''获取用户收货地址'''
        address_list = Address.objects.filter(user=user, is_deleted=False)  # 获取用户所有收货地址查询集
        addresses = []  # 定义列表存储用户收货地址信息
        for address in address_list:
            addresses.append({
                "id": address.id,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "receiver": address.receiver
            })

        '''返回响应数据'''
        return JsonResponse({
            "code": 0,
            "errmsg": "OK",
            "context": {
                "skus": skus,
                "addresses": addresses,
                "freight": 0
            }
        })


class OrderCommitView(View):

    def post(self, request):
        """
        提交订单
        :param request:
        :return:
        """
        # 1. 提取参数
        data = json.loads(request.body.decode())
        address_id = data.get('address_id')
        pay_method = data.get('pay_method')
        # 2. 校验参数
        if not all([address_id, pay_method]):
            return JsonResponse({'code': 400, 'errmsg': '参数缺失'})
        if not isinstance(address_id, int):
            return JsonResponse({'code': 400, 'errmsg': '参数错误'})
        if pay_method not in [1, 2]:
            return JsonResponse({'code': 400, 'errmsg': '参数错误'})
        # 3. 新建订单信息表（OrderInfo），用来保存用户的订单编号、总数量、总价格、地址、运费、支付方式
        # # order_id订单主键，自己构造：(1)、不同的用户必须唯一 （2）针对同一个用户也是唯一
        # 针对需求(1)，可以把用户的id拼接；针对需求(2)拼接当前生成订单的时间戳字符串
        # 20200630160756000002
        # timezone.now() # 返回0时区表示的当前时间点对象
        # timezone.localtime() # 返回当前时区表示的当前时间点对象
        localtime = timezone.localtime()
        # 20200630160756 ---->  年月日时分秒 ----> "%Y%m%d%H%M%S"
        # 200630160756 ---->  年月日时分秒 ----> "%y%m%d%H%M%S"
        local_time_str = localtime.strftime('%Y%m%d%H%M%S')  # 将时间对象变成指定的字符串格式
        # 20200630160756000002

        order_id = local_time_str + '%06d' % request.user.id

        with transaction.atomic():

            # 记录一个事物的执行的节点
            save_id = transaction.savepoint()

            order = OrderInfo(
                order_id=order_id,
                user=request.user,
                address_id=address_id,
                pay_method=pay_method,
                total_count=0,  # 先设置为0，后面增加sku商品后再进行修改
                total_amount=0,
                freight=Decimal('10.0')
            )
            order.save()

            # 4. 新建订单商品信息表（OrderGoods），用来保存用户具体的商品信息、数量、价格
            # 4.1 从数据获取用户购物车数据
            redis_cart, redis_selected = get_redis_carts(request)
            # 4.2 根据选中的sku商品，添加到OrderGoods
            cart_data = {}
            for sku_id, count in redis_cart.items():
                if sku_id in redis_selected:   # 只保存被选中的商品
                    cart_data[int(sku_id)] = {
                        'count': int(count),
                        'selected': sku_id in redis_selected
                    }
            sku_ids = cart_data.keys()
            for sku_id in sku_ids:
                # sku:sku对象
                # 每在购物车遍历出一个sku商品，就要往订单信息中间表（OrderGoods表）插入一条数据
                while True:
                    sku = SKU.objects.get(pk=sku_id)

                    old_stock = sku.stock
                    old_sales = sku.sales

                    # 下单数量
                    count = cart_data[sku_id]['count']

                    # 判断库存
                    if count > old_stock:
                        # 如果库存不足，则回滚到新建订单信息之前
                        transaction.savepoint_rollback(save_id)
                        return JsonResponse({'code': 400, 'errmsg': "库存不足"})

                    new_stock = old_stock - count
                    new_sales = old_sales + count

                    result = SKU.objects.filter(
                        id=sku_id, stock=old_stock).update(
                        stock=new_stock, sales=new_sales
                        )
                    if result == 0:
                        continue
                    break

                order_goods = OrderGoods(
                    order=order,
                    sku=sku,
                    count=count,
                    price=sku.price
                )

                # 销量增加，库存减少
                # sku.sales += count
                # sku.stock -= count
                # sku.save()

                # 同类spu商品增加
                spu = sku.goods
                spu.sales += count
                spu.save()

                # # 订单的总商品数量累加
                order.total_count += count
                order.total_amount += (sku.price * count)
                # 插入订单表数据
                order_goods.save()

            # 运费金额加入总金额
            order.total_amount += order.freight
            order.save()

        # 5. 下单成功后，需要把用户的购物车信息删除（把redis数据库中的数据删除）
        conn = get_redis_connection('carts')
        for sku_id in redis_selected:
            conn.hdel('carts_%s' % request.user.id, sku_id)
            conn.srem('selected_%s' % request.user.id, sku_id)
        # 6. 构建响应返回
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'order_id': order_id})
